package com.yunc.modules.oa.service.impl;

import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yunc.modules.oa.entity.dto.ActivitiDTO;
import com.yunc.modules.oa.entity.dto.UserDTO;
import com.yunc.modules.oa.entity.vo.ActivitiNodeVO;
import com.yunc.modules.oa.entity.vo.ActivitiUserVO;
import com.yunc.modules.oa.mapper.ActivitiMapper;
import com.yunc.modules.oa.service.IActivitiService;
import com.yunc.modules.sys.entity.SysUser;
import com.yunc.modules.sys.service.ISysUserService;
import org.activiti.bpmn.model.*;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.runtime.ProcessInstance;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.InputStream;
import java.util.*;

/**
 * 流程查询
 *
 * @author congcong tao
 * @date 2019/2/20 16:51
 */
@Service
public class ActivitiServiceImpl implements IActivitiService {

    @Autowired
    private ActivitiMapper activitiMapper;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private ISysUserService sysUserService;

    @Override
    public Page taskStartPage(Page<ActivitiDTO> page, ActivitiDTO activitiDTO) {
        List<ActivitiDTO> tableList = activitiMapper.selectTaskStartList(page, activitiDTO);
        return page.setRecords(tableList);
    }

    @Override
    public Page taskCheckingPage(Page<ActivitiDTO> page, ActivitiDTO activitiDTO) {
        List<ActivitiDTO> tableList = activitiMapper.selectTaskCheckingList(page, activitiDTO);
        return page.setRecords(tableList);
    }

    @Override
    public Page taskCheckedPage(Page<ActivitiDTO> page, ActivitiDTO activitiDTO) {
        List<ActivitiDTO> tableList = activitiMapper.selectTaskCheckedList(page, activitiDTO);
        return page.setRecords(tableList);
    }

    @Override
    public Page<UserDTO> groupUserPage(Page<UserDTO> page, UserDTO userDTO) {
        List<UserDTO> tableList = activitiMapper.groupUserPage(page, userDTO);
        return page.setRecords(tableList);
    }

    @Override
    public Page<UserDTO> userPage(Page<UserDTO> page, UserDTO userDTO) {
        List<UserDTO> tableList = activitiMapper.userPage(page, userDTO);
        return page.setRecords(tableList);
    }

    @Override
    public InputStream getDiagram(String processInstanceId) {
        //获得流程实例
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId).singleResult();
        String processDefinitionId = StringUtils.EMPTY;
        if (processInstance == null) {
            //查询已经结束的流程实例
            HistoricProcessInstance processInstanceHistory = historyService.createHistoricProcessInstanceQuery()
                            .processInstanceId(processInstanceId).singleResult();
            if (processInstanceHistory == null) {
                return null;
            } else {
                processDefinitionId = processInstanceHistory.getProcessDefinitionId();
            }
        } else {
            processDefinitionId = processInstance.getProcessDefinitionId();
        }

        //使用宋体
        String fontName = "宋体";
        //获取BPMN模型对象
        BpmnModel model = repositoryService.getBpmnModel(processDefinitionId);
        //获取流程实例当前的节点，需要高亮显示
        List<String> currentActs = Collections.EMPTY_LIST;
        if (processInstance != null) {
            currentActs = runtimeService.getActiveActivityIds(processInstance.getId());
        }
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        return processEngine.getProcessEngineConfiguration()
                .getProcessDiagramGenerator()
                .generateDiagram(model, "png", currentActs, new ArrayList<>(),
                        fontName, fontName, fontName, null, 1.0);
    }

    @Override
    public List<ActivitiNodeVO> iteratorNextNodes(Map<String, Object> params, List<SequenceFlow> outgoingFlows, List<ActivitiNodeVO> userTaskList) {
        if (outgoingFlows == null || outgoingFlows.size() == 0) {
            return userTaskList;
        }
        if (MapUtil.isEmpty(params)) {
            iteratorNextNodes(outgoingFlows, userTaskList);
            return userTaskList;
        }
        List<SequenceFlow> newOutgoingFlows = new ArrayList<>();
        for (SequenceFlow sequenceFlow : outgoingFlows) {
            FlowElement targetFlowElement = sequenceFlow.getTargetFlowElement();
            if (targetFlowElement instanceof UserTask) {
                UserTask userTask = (UserTask) targetFlowElement;
                HashMap<String, UserTask> objectObjectHashMap = new HashMap<>(1);
                if (!StringUtils.contains(userTask.getAssignee(), "${")) {
                    objectObjectHashMap.put(userTask.getId(), userTask);
                    ActivitiNodeVO activitiNode = new ActivitiNodeVO();
                    activitiNode.setId(userTask.getId());
                    activitiNode.setName(userTask.getName());
                    SysUser sysUser = sysUserService.getById(userTask.getAssignee());
                    if (sysUser != null) {
                        List<ActivitiUserVO> activitiUserVOS = new ArrayList<>();
                        activitiUserVOS.add(new ActivitiUserVO(userTask.getAssignee(), sysUser.getUserName()));
                        activitiNode.setActivitiUserList(activitiUserVOS);
                    }
                    userTaskList.add(activitiNode);
                } else {
                    String conditionExpression = sequenceFlow.getConditionExpression();
                    if (StringUtils.isNotEmpty(conditionExpression)) {
                        // 如果有条件参数，需要比较eval，满足的留下
                        if (MapUtil.isNotEmpty(params)) {
                            int begin = conditionExpression.indexOf("{");
                            int end = conditionExpression.indexOf("}");
                            String condition = conditionExpression.substring(begin + 1, end);
                            try {
                                boolean result = false;
                                ScriptEngineManager manager = new ScriptEngineManager();
                                ScriptEngine engine = manager.getEngineByName("js");
                                for (Map.Entry<String, Object> entry : params.entrySet()) {
                                    engine.put(entry.getKey(), entry.getValue());
                                }
                                result = (Boolean) engine.eval(condition);
                                if (result) {
                                    objectObjectHashMap.put(conditionExpression, userTask);
                                    ActivitiNodeVO activitiNode = new ActivitiNodeVO();
                                    activitiNode.setId(userTask.getId());
                                    activitiNode.setName(userTask.getName());
                                    activitiNode.setCondition(conditionExpression);
                                    userTaskList.add(activitiNode);
                                }
                            } catch (ScriptException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            } else if (targetFlowElement instanceof ExclusiveGateway) {
                ExclusiveGateway exclusiveGateway = (ExclusiveGateway) targetFlowElement;
                newOutgoingFlows.addAll(exclusiveGateway.getOutgoingFlows());
            }
        }
        if (newOutgoingFlows != null && newOutgoingFlows.size() > 0) {
            iteratorNextNodes(params, newOutgoingFlows, userTaskList);
        }
        return userTaskList;
    }

    public List<ActivitiNodeVO> iteratorNextNodes(List<SequenceFlow> outgoingFlows, List<ActivitiNodeVO> userTaskList) {
        if (outgoingFlows == null || outgoingFlows.size() == 0) {
            return userTaskList;
        }
        List<SequenceFlow> newOutgoingFlows = new ArrayList<>();
        for (SequenceFlow sequenceFlow : outgoingFlows) {
            FlowElement targetFlowElement = sequenceFlow.getTargetFlowElement();
            if (targetFlowElement instanceof EndEvent) {
                EndEvent endEvent = (EndEvent) targetFlowElement;
                ActivitiNodeVO activitiNode = new ActivitiNodeVO();
                activitiNode.setId(endEvent.getId());
                activitiNode.setName(endEvent.getName());
                activitiNode.setIsLastTask(Boolean.TRUE);
                userTaskList.add(activitiNode);
            } else if (targetFlowElement instanceof UserTask) {
                UserTask userTask = (UserTask) targetFlowElement;
                // 发起人，驳回操作
                ActivitiNodeVO activitiNode = new ActivitiNodeVO();
                activitiNode.setId(userTask.getId());
                if (!StringUtils.contains(userTask.getAssignee(), "${")) {
                    // 查询办理人
                    SysUser sysUser = sysUserService.getById(userTask.getAssignee());
                    if (sysUser != null) {
                        List<ActivitiUserVO> activitiUserVOS = new ArrayList<>();
                        activitiUserVOS.add(new ActivitiUserVO(userTask.getAssignee(), sysUser.getUserName()));
                        activitiNode.setActivitiUserList(activitiUserVOS);
                    }
                }
                if (StringUtils.equals(userTask.getAssignee(), "${staff}")) {
                    activitiNode.setName("驳回");
                } else {
                    activitiNode.setName(userTask.getName());
                }
                String conditionExpression = sequenceFlow.getConditionExpression();
                if (StringUtils.isNotEmpty(conditionExpression)) {
                    // 需要将选择条件写死，在bpmn中，${result == 0}修改参数来进行条件选择判断
                    activitiNode.setCondition(conditionExpression.substring(12, 13));
                }
                userTaskList.add(activitiNode);
            } else if (targetFlowElement instanceof ExclusiveGateway) {
                ExclusiveGateway exclusiveGateway = (ExclusiveGateway) targetFlowElement;
                newOutgoingFlows.addAll(exclusiveGateway.getOutgoingFlows());
            }
        }
        if (newOutgoingFlows != null && newOutgoingFlows.size() > 0) {
            iteratorNextNodes(newOutgoingFlows, userTaskList);
        }
        return sortActivitiNode(userTaskList);
    }

    private List<ActivitiNodeVO> sortActivitiNode(List<ActivitiNodeVO> list) {
        Collections.sort(list, new Comparator<ActivitiNodeVO>() {
            @Override
            public int compare(ActivitiNodeVO o1, ActivitiNodeVO o2) {
                if (Float.parseFloat(o1.getCondition()) > Float.parseFloat(o2.getCondition())) {
                    return -1;
                } else if (Float.parseFloat(o1.getCondition()) == Float.parseFloat(o2.getCondition())) {
                    return 0;
                } else {
                    return 1;
                }
            }
        });
        return list;
    }
}
